Preamble

This notebook collects analysis and visualization of all data related to nitrate inventories and other mixed-layer properties as compiled in the previous notebook.

All figures exported from this notebook are prefixed with FIGURE_FN-COMP_.

In [1]:
%load_ext autoreload
%autoreload 2
%run imports.py
In [ ]:
pd.read_feather('../data/no3-compilation/da')
In [27]:
def load_data():
    # df_per_station, df = load_data()
    df_per_station = pd.read_feather('../data/no3-compilation/database-per-stn.feather')
    df = pd.read_feather('../data/no3-compilation/database.feather')
    return df_per_station, df
In [3]:
# Define dimensions
dims = dict(
    reg_name=hv.Dimension('reg_name', label='Region'),
    ntr0=hv.Dimension('ntr0', label='Sfc. NO₃', unit='µM', range=(0,13)),
    doy=hv.Dimension('doy', label='Day of the year', range=(0,360)),
    lon=hv.Dimension('lon', label='Longitude', unit='°E'),
    lat=hv.Dimension('lat', label='Latitude', unit='°N'),
    delta_sigth=hv.Dimension('delta_sigth', label='Δσ-θ', unit='kg m⁻³'),
    strat=hv.Dimension('strat', label='N²', unit='s⁻²'),
    logstrat=hv.Dimension('logstrat', label='log10 N²', unit='s⁻²'),
    no3_sfc_winter = hv.Dimension('no3_sfc_winter', label='Pre-bloom sfc. NO₃ ', unit='µM', range=(-.5,13))
)

Maps of key quantities

In [4]:
df, dfp, _ = load_data()
/Users/doppler/anaconda3/envs/nitrateflux/lib/python3.7/site-packages/IPython/core/interactiveshell.py:3249: DtypeWarning: Columns (66,67) have mixed types. Specify dtype option on import or set low_memory=False.
  if (await self.run_code(code, result,  async_=asy)):
In [5]:
def logmean(x):
    return np.nanmedian(np.log10(x))

options = (
    opts.HexTiles(),
    opts.HexTiles('ntr0', cmap=cmocean.cm.matter_r),
    opts.HexTiles('delta_sigth', aggregator=logmean),
    opts.HexTiles('no3sig_nc', color_levels=8),
    opts.HexTiles('no3sig_mld', color_levels=8),
    opts.HexTiles('deltanc', symmetric=True, cmap='PuOr'),
    opts.Polygons(line_color='k', fill_color=None, line_width=3),
    opts.Shape(line_width=1, color='w'),
)

griddict = {
    (season, var):
    gv.HexTiles(df.loc[df.season==season].dropna(subset=[var]), ['lon', 'lat'], var, label=var) 
    for season in ['winter', 'summer']
    for var in ['nc', 'mld', 'ntr0', 
                'delta_sigth']

}


gs = hv.GridSpace(griddict, kdims=['season', 'variable'])
gs = gs.redim.range(deltanc=(-50, 50), mld=(0,100), nc=(0.1,100), nc0=(0.1,60))#, delta_sigth=(.05,3))
l = gs * land

html

ll = l[:, 'delta_sigth'].opts(*opts_map_bk, clone=True).opts( # opts.HexTiles(hooks=[logcolor_ticks([.2, .3, .5, 1, 3, 5])], clim=(-.7, .5), toolbar=None), opts.HexTiles( colorbar=False, clim=(-.7, .5), frame_height=400, frame_width=400, # height=400, width=400, ), clone=True ) # Pickler.save(ll, '../nb_fig/FIGURE_NO3-COMP_map_stratification') # hv.save(ll, '../nb_fig/FIGURE_NO3-COMP_map_stratification', fmt='png') ll.opts(opts.GridSpace(height=2000, width=2000))hv.renderer('bokeh').theme = None

mpl output

Make custom diverging color map:

In [6]:
# cm = colorcet.b_diverging_linear_bjy_30_90_c45[::-1]
cm = colorcet.b_diverging_bwr_40_95_c42[::-1]
cm = cm[:127:4] + cm[127:]
In [7]:
obj = l.opts(
    opts_map_mpl + [
        opts.HexTiles(clim=(0,5), backend='matplotlib'),
    ]
)
In [8]:
fig = mplrender_map(obj['summer', 'ntr0'], fname='../nb_fig/FIGURE_NO3-COMP_map_no3_summer')

fig
Out[8]:
# need diverging colour map fig = mplrender_map(obj['summer', 'ntr0'], fname='../nb_fig/FIGURE_NO3-COMP_map_no3_summer_limiting') fig
In [9]:
fig = mplrender_map(obj['winter', 'ntr0'], fname='../nb_fig/FIGURE_NO3-COMP_map_no3_winter')

fig
Out[9]:

Seasonality

In [10]:
df, dfp = load_data()
/Users/doppler/anaconda3/envs/nitrateflux/lib/python3.7/site-packages/IPython/core/interactiveshell.py:3249: DtypeWarning: Columns (66,67) have mixed types. Specify dtype option on import or set low_memory=False.
  if (await self.run_code(code, result,  async_=asy)):

Seasonality by regions

In [13]:
loc = gv.Points(df, ['lon', 'lat'], [])
ntr = hv.Scatter(df, 'doy', ['ntr0'])

DataLink(loc,ntr)

l = loc*land*gv.feature.rivers + ntr 
l = l.redim(**dims).cols(1)

options = (
    opts.Scatter(
        tools=['lasso_select', 'box_select'], active_tools=['lasso_select'], 
        color='lightblue', size=5, selection_color='orange',
        height=300, width=600
    ),
    opts.Points(
        tools=['lasso_select'], active_tools=['lasso_select'],
        projection=ccrs.NorthPolarStereo(),
        color='lightblue', size=3, selection_color='orange',
        height=400, aspect=1,
    ),
    opts.Feature(
        fill_color='wheat', line_color='black',
        scale='50m'
    ),
    opts.Feature('Rivers', line_color='blue', scale='110m'),
)
l = l.opts(*options)

hv.save(l, '../nb_fig/FIGURE_NO3-COMP_chart_seasonal_cycle.html')
l
Out[13]:

Make static matplotlib plot for paper

In [25]:
def annual_cycle(v):
    """Plots seasonal cycle of variable v"""
    sc = hv.Scatter(df, kdims=['doy'], 
                      vdims=[v, 
                             'nc', 'lat', 'lon', 'mld', 'ntr0', 'nc0', 'reg_name'], 
                      label=v
                     ).groupby('reg_name')
    err = hvu.bin_average(sc, bins=np.arange(0,361,30))
    return sc *  err * err.map(hv.Curve, hv.Dataset) * err.map(hv.Scatter, hv.Dataset)

l = annual_cycle('ntr0').layout().cols(3)
l = l.opts(*opts_timeseries_mpl + [
    opts.Scatter(title_format='asd{group}',
        invert_yaxis=False, backend='matplotlib', 
        xlabel='', #ylabel='',
    ),
    opts.Layout()
])
l = l.redim(**dims)

# hv.save(l, '../nb_fig/FIGURE_NO3-COMP_chart_seasonal_cycle.png')
with plt.style.context('styles/sparse.mplstyle'):
    fig = mplrender(l)
    fig.subplots_adjust(wspace=.25, hspace=.08, left=0.2)
    fig.set_size_inches((12,8))
    
fname = '../nb_fig/FIGURE_NO3-COMP_chart_seasonal_cycle'
fig.savefig(fname+'.png')
fig.savefig(fname+'.pdf')
fig
/Users/doppler/papers/nitrateflux/nb/utils/holoviews/operation.py:50: RuntimeWarning: Mean of empty slice
  y_avg[k] = self.p.avg_fun(y_sel)
/Users/doppler/anaconda3/envs/nitrateflux/lib/python3.7/site-packages/numpy/lib/nanfunctions.py:1330: RuntimeWarning: Mean of empty slice
  return np.nanmean(a, axis, out=out, keepdims=keepdims)
Out[25]:

Laptev Nitrate profiles

In [16]:
df_single, df = load_data()
/Users/doppler/anaconda3/envs/nitrateflux/lib/python3.7/site-packages/IPython/core/interactiveshell.py:3249: DtypeWarning: Columns (66,67) have mixed types. Specify dtype option on import or set low_memory=False.
  if (await self.run_code(code, result,  async_=asy)):
In [17]:
(
    df.loc[df.lat.between(76, 77) & df.lon.between(124, 128)]
    .hvplot('nitrate', 'depth', by='station')
    .opts(invert_yaxis=True)
)
Out[17]:
In [18]:
(
    df.loc[df.lat.between(76, 77) & df.lon.between(124, 128)]
    .hvplot('sigth', 'depth', by='station')
    .opts(invert_yaxis=True)
)
Out[18]:

Gradient:

In [19]:
3/20
Out[19]:
0.15
In [20]:
(27-23)/20
Out[20]:
0.2

[do later] Interannual trends

obs:

- NC deepening in S Beaufort

to do: make 2dim hextiles aggregator, then plot hextiles of trends and significance

In [38]:
df_per_station, df = load_data()

df = df.melt(['year', 'season', 'reg_name'], ['ntr0', 'nc', 'nc0']).dropna(subset=['season'])
df = df.loc[~df.reg_name.isnull()]
In [39]:
df.reg_name.unique()
Out[39]:
array(['Chukchi Sea', 'Eurasian Basin', 'Makarov Basin',
       'Southern Beaufort', 'Fram Strait (East)', 'Canadian Archipelago',
       'Barents Sea', 'Baffin Bay', 'Canada Basin'], dtype=object)
In [40]:
m = df.hvplot.scatter('year', 'value', groupby=['reg_name', 'season', 'variable'])

from utils.holoviews.element import Regression

l=m*m.map(Regression, 'Scatter')
In [49]:
%%opts Scatter [ frame_width=600 frame_height=400 show_grid=True invert_yaxis=True, legend_position='top']
l.overlay('season')#.layout('reg_name').cols(1)
/Users/doppler/papers/nitrateflux/nb/utils/holoviews/operation.py:130: RankWarning: Polyfit may be poorly conditioned
  p = np.polyfit(x=xp, y=yp, deg=1)
Out[49]:
dm = hv.DynamicMap(m['summer', 'Baffin Bay']) dm.callback.inputs(df .assign(year=df.date.dt.year) .groupby(['year','reg_name', 'season']) .mean()['nc'] .unstack()['winter'] .unstack()#['Canada Basin']#Southern Beaufort .interpolate() .plot(linestyle='-', marker='s') ) # plt.xlim(1980,2010)(df .assign(year=df.date.dt.year) .groupby(['year','reg_name', 'season']) .mean()['ntr0'] .unstack()['summer'] .unstack()#['Southern Beaufort'] .interpolate() .plot(linestyle='-', marker='.') )d = df.copy()#.loc[(df.nc>1)] d = d.assign(r=d.nc/d.mld).assign(dm=d.nc-d.mld) d.groupby(['season', 'reg_name']).mean()[['r', 'dm', 'mld', 'nc']]

[unused] Scatter plots: Relations

deltanc vs surface NO3

%%opts Scatter [show_grid=True] f = hv.Scatter(df.assign(r=df.nc0-df.mld), kdims=['r'], vdims=['ntr0', 'reg_name'] ).groupby('reg_name').layout().cols(3) ( f * binavg(f, bins=np.arange(0,361,30)) )

NC vs MLD...

%%opts Points [color_index='ntr0' show_grid=True colorbar=True logz=True width=700] %%opts Points [tools=['hover']] (line_color='k' size=5) %%opts Points (cmap='viridis') # (cmap='Category20') ( hv.Points(df, kdims=['mld', 'nc'], vdims=['month', 'reg_name', 'season', 'ntr0'] ).groupby('reg_name') * hv.Curve(dict(x=[0, 130], y=[0,130])) ).redim.range(mld=(-5, 500))%%opts Scatter [width=600 height=400 show_grid=True] %%opts Scatter [color_index='month' colorbar=True] (cmap='viridis' size=4) # (cmap='Category10') sc = hv.Scatter(df, kdims=['nc'], vdims=['ntr0', 'season', 'month', 'mld', 'reg_name']) sc.groupby('reg_name').redim.range(nc=(2,None), ntr0=(-.1, 1.5))d = dfr.loc[dfr.reg_name.str.contains('Barents') & (dfr.nc>1)] d = d.assign(r=d.nc/d.mld).assign(dm=d.nc-d.mld)